package com.sumainfor.common.utlis;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import com.sumainfor.common.entity.AuthToken;
import com.sumainfor.common.entity.WxPaySendData;
import com.sumainfor.common.wechat.WeChatConfig;
import com.sumainfor.common.wechat.WeChatConstant;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.servlet.http.HttpServletRequest;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.List;

import net.sf.json.JSONObject;


/**
 * 主要进行微信公众号授权请求工具类
 * 
 * @ClassName: AuthUtil
 * @Description: TODO(这里用一句话描述这个类的作用)
 * @author xiaoma
 * @date 2019年2月11日
 */
public class AuthUtil {

	public static JSONObject doGetJson(String url)
			throws ClientProtocolException, IOException {
		JSONObject jsonObject = null;
		DefaultHttpClient client = new DefaultHttpClient();
		HttpGet httpGet = new HttpGet(url);
		HttpResponse response = client.execute(httpGet);
		HttpEntity entity = response.getEntity();
		if (entity != null) {
			String result = EntityUtils.toString(entity, "UTF-8");
			jsonObject = JSONObject.fromObject(result);
		}
		httpGet.releaseConnection();
		return jsonObject;
	}

	/**
	 * 根据code获取微信授权access_token
	 * @throws Exception
	 */
	public static AuthToken getTokenByAuthCode(String code) throws Exception {
		AuthToken authToken;
		JSONObject jsonObject = null;
		StringBuilder json = new StringBuilder();
		try {
			URL url = new URL(WeChatConstant.GET_AUTHTOKEN_URL + "appid="
					+ WeChatConfig.APP_ID + "&secret="
					+ WeChatConfig.APP_SECRET + "&code=" + code
					+ "&grant_type=authorization_code");
			URLConnection uc = url.openConnection();
			BufferedReader in = new BufferedReader(new InputStreamReader(
					uc.getInputStream()));
			String inputLine;
			while ((inputLine = in.readLine()) != null) {
				json.append(inputLine);
			}
			in.close();
			// 将json字符串转成javaBean
			ObjectMapper om = new ObjectMapper();
//			authToken = readValue(json.toString(),AuthToken.class);
			authToken=om.readValue(json.toString(), AuthToken.class);

		} catch (Exception e) {
			throw new Exception("微信工具类:根据授权code获取access_token异常", e);
		}
		return authToken;
	}

	/**
	 * 微信支付签名算法sign
	 *
	 * @param characterEncoding
	 * @param parameters
	 * @return
	 */
	public static String createSign(String characterEncoding,
									SortedMap<String, Object> parameters,String AppSecret) {
		StringBuffer sb = new StringBuffer();
		Set es = parameters.entrySet();// 所有参与传参的参数按照accsii排序（升序）
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			Object v = entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k)
					&& !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}

		sb.append("key=" + AppSecret);
		System.out.println("字符串:" + sb.toString());
		String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding)
				.toUpperCase();
		return sign;
	}

	/**
	 * 将微信服务器发送的Request请求中Body的XML解析为Map
	 *
	 * @param request
	 * @return
	 * @throws Exception
	 */
	public static Map<String, String> parseRequestXmlToMap(
			HttpServletRequest request) throws Exception {
		// 解析结果存储在HashMap中
		Map<String, String> resultMap;
		InputStream inputStream = request.getInputStream();
		resultMap = parseInputStreamToMap(inputStream);
		return resultMap;
	}

	/**
	 * 将输入流中的XML解析为Map
	 *
	 * @param inputStream
	 * @return
	 * @throws DocumentException
	 * @throws IOException
	 */
	public static Map<String, String> parseInputStreamToMap(
			InputStream inputStream) throws DocumentException, IOException {
		// 解析结果存储在HashMap中
		Map<String, String> map = new HashMap<String, String>();
		// 读取输入流
		SAXReader reader = new SAXReader();
		Document document = reader.read(inputStream);
		// 得到xml根元素
		Element root = document.getRootElement();
		// 得到根元素的所有子节点
		List<Element> elementList = root.elements();
		// 遍历所有子节点
		for (Element e : elementList) {
			map.put(e.getName(), e.getText());
		}
		// 释放资源
		inputStream.close();
		return map;
	}

	/**
	 * 将String类型的XML解析为Map
	 *
	 * @param str
	 * @return
	 * @throws Exception
	 */
	public static Map<String, String> parseXmlStringToMap(String str)
			throws Exception {
		Map<String, String> resultMap;
		InputStream inputStream = new ByteArrayInputStream(
				str.getBytes("UTF-8"));
		resultMap = parseInputStreamToMap(inputStream);
		return resultMap;
	}

	/**
	 * 解析微信服务器发来的请求
	 *
	 * @param inputStream
	 * @return 微信返回的参数集合
	 * @throws Exception
	 */
	public static SortedMap<String, Object> parseXml(InputStream inputStream)
			throws Exception {
		SortedMap<String, Object> map = new TreeMap<String, Object>();
		try {
			// 获取request输入流
			SAXReader reader = new SAXReader();
			Document document = reader.read(inputStream);
			// 得到xml根元素
			Element root = document.getRootElement();
			// 得到根元素所有节点
			List<Element> elementList = root.elements();
			// 遍历所有子节点
			for (Element element : elementList) {
				map.put(element.getName(), element.getText());
			}
			// 释放资源
			inputStream.close();
		} catch (Exception e) {
			throw new Exception("微信工具类:解析xml异常", e);
		}
		return map;
	}

	/**
	 * 扩展xstream,使其支持name带有"_"的节点
	 */
	public static XStream xStream = new XStream(new DomDriver("UTF-8",
			new XmlFriendlyNameCoder("-_", "_")));

	/**
	 * 请求参数转换成xml
	 *
	 * @param data
	 * @return xml字符串
	 */
	public static String sendDataToXml(WxPaySendData data) {
		xStream.autodetectAnnotations(true);
		xStream.alias("xml", WxPaySendData.class);
		return xStream.toXML(data);
	}

	/**
	 * 获取当前时间戳
	 *
	 * @return 当前时间戳字符串
	 */
	public static String getTimeStamp() {
		return String.valueOf(System.currentTimeMillis());
	}

	/**
	 * 获取指定长度的随机字符串
	 *
	 * @param length
	 * @return 随机字符串
	 */
	public static String getRandomStr(int length) {
		String base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
		Random random = new Random();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < length; i++) {
			int number = random.nextInt(base.length());
			sb.append(base.charAt(number));
		}
		return sb.toString();
	}

	/**
	 * XML格式字符串转换为Map
	 *
	 * @param strXML XML字符串
	 * @return XML数据转换后的Map
	 * @throws Exception
	 */
	public static Map<String, String> xmlToMap(String strXML) throws Exception {
		try {
			Map<String, String> data = new HashMap<String, String>();
			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
			InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
			org.w3c.dom.Document doc = documentBuilder.parse(stream);
			doc.getDocumentElement().normalize();
			NodeList nodeList = doc.getDocumentElement().getChildNodes();
			for (int idx = 0; idx < nodeList.getLength(); ++idx) {
				Node node = nodeList.item(idx);
				if (node.getNodeType() == Node.ELEMENT_NODE) {
					org.w3c.dom.Element element = (org.w3c.dom.Element) node;
					data.put(element.getNodeName(), element.getTextContent());
				}
			}
			try {
				stream.close();
			} catch (Exception ex) {
				// do nothing
			}
			return data;
		} catch (Exception ex) {
//            WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
			throw ex;
		}

	}

}
